﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using SimpleServiceBus.Messages.Management.Monitoring;
using SimpleServiceBus.Utilities;
using SimpleServiceBus.Utilities.Email;

namespace SimpleServiceBus.EndpointManagement.Server.Utilities
{
    public class ExceptionNotificationGoverner
    {
        private const string SingleErrorSubjectTemplate = @"Endpoint Exception for {0}, {1}";

        private const string MultiErrorSubject =
            @"Multiple Exceptions have been encountered at one or more SSB endpoints.";

        private const string ErrorEmailTemplate =
            @"An exception occurred on endpoint {0} at {1} while processing a message with a MessageID of {2}. {4} Exception: {4}{4} {3}";

        public TimeSpan EmailAggregationDelay = TimeSpan.FromSeconds(10);
        public TimeSpan EmailAggregationMaxDelay = TimeSpan.FromMinutes(1);
       

        private Dictionary<string, BufferedOperationAggregator<EndpointErrorNotification>> _targets =
            new Dictionary<string, BufferedOperationAggregator<EndpointErrorNotification>>(StringComparer.OrdinalIgnoreCase);

        private readonly object _threadLock = new object();

        public void SubmitErrorNotification(string destinationEmail,EndpointErrorNotification error,IEmailService mailMan)
        {
            lock(_threadLock)
            {
                BufferedOperationAggregator<EndpointErrorNotification> governer;
                if (_targets.ContainsKey(destinationEmail))
                    governer = _targets[destinationEmail];
                else
                {
                    governer = new BufferedOperationAggregator<EndpointErrorNotification>
                                              {
                                                  Delay = EmailAggregationDelay,
                                                  MaxDelay = EmailAggregationMaxDelay,
                                                  IdleAction = (errors)=> SendMessages(destinationEmail,errors,mailMan)
                                                  
                                              };
                    _targets.Add(destinationEmail, governer);
                }

                governer.SubmitEvent(error);
            }
        }

        private static void SendMessages(string destinationEmail,IList<EndpointErrorNotification> errors,IEmailService mailMan)
        {
            if (errors == null || errors.Count < 1)
                return;

            string body;
            string subject;
            string attachmentFileName = null;
            byte[] attachment = null;


            if (errors.Count == 1)
            {
                subject = String.Format(SingleErrorSubjectTemplate, errors[0].EndpointID, errors[0].ErrorMessage.Elide(30));
                body = String.Format(ErrorEmailTemplate, errors[0].EndpointID, errors[0].StatusTime,
                                            errors[0].FailedMessageID, errors[0].ErrorMessage, Environment.NewLine);
            }
            else
            {
                subject = MultiErrorSubject;
                body = "See attached error log for details.";
                attachmentFileName = "errors.txt";

                var errorText = new StringBuilder();
                foreach (EndpointErrorNotification errorNotification in errors)
                {
                    errorText.AppendFormat(ErrorEmailTemplate, errorNotification.EndpointID,
                                           errorNotification.StatusTime,
                                           errorNotification.FailedMessageID, errorNotification.ErrorMessage,
                                           Environment.NewLine);
                    errorText.AppendLine("--------------------------------");
                }
                attachment = Encoding.UTF8.GetBytes(errorText.ToString());
            }

            mailMan.Send(subject, body, attachmentFileName, attachment, destinationEmail);

            
        }

    }

    
}
